/**
 *  TypeStack.java : IceBird project
 *  7:13:06 
 */
package icebird.compiler.bytecode;

import icebird.metadata.BasicType;
import icebird.metadata.ReferenceType;

/**
 * Represents type stack(Primarly for checking).
 * @author Sergey Shulepoff[Knott]
 */
public final class TypeStack {
	
	private BasicType[] stack;
	private int peek;
	
	/**
	 * Creates type stack.
	 */
	public TypeStack() {
		stack = new BasicType[8];
		peek = 0;
	}
	
	public TypeStack(TypeStack src) {
		stack = new BasicType[src.stack.length];
		peek = src.peek;
		
		System.arraycopy(src.stack, 0, stack, 0, src.stack.length);
	}
	
	/**
	 * Empty the stack.
	 * @return void
	 */
	public void clear() {
		peek = 0;
	}
	
	/**
	 * Is stack empty?
	 * @return boolean
	 */
	public boolean isEmpty() {
		return (peek == 0);
	}
	
	/**
	 * Gets size of stack.
	 * @return int
	 */
	public int getSize() {
		return peek;
	}
	
	/**
	 * Push type into stack.
	 * @return void
	 */
	public void push(BasicType obj) {
		// Compare peek and internal
		// array which represents stack.
		if (peek == stack.length) {
			grow();
		}
		
		stack[peek++] = obj;
	}
	
	/**
	 * Pop type from stack.
	 * @return BasicType
	 */
	public BasicType pop() {
		if (peek <= 0) {
			throw new RuntimeException("Stack is empty.");
		}
		
		return stack[--peek];
	}
	
	/**
	 * Pop type from stack, and except special.
	 * @return BasicType
	 */
	public BasicType pop(BasicType except) {
		BasicType obj = pop();
		
		if (except instanceof ReferenceType) {
			if (obj instanceof ReferenceType) {
				return obj;
			} else {
				throw new RuntimeException("Type not excepted, " + obj);
			}
		}
		
		if (except != obj) {
			throw new RuntimeException("Type not excepted, " + obj);
		}
		
		return obj;
	}
	
    /**
     * Grow the stack space.
     *  
     */
    private final void grow() {
        final BasicType[] tmp = new BasicType[stack.length * 2];
        
        System.arraycopy(stack, 0, tmp, 0, stack.length);
        stack = tmp;
    }
}
